/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.gatech.gellinservlet.model;
import java.io.*;
import java.util.logging.Level;

/**
 *
 * @author Tyler Powell
 */
public abstract class User implements IDable , Serializable 
{
    private static final long serialVersionUID = 1L;
    
    public static final int MAXATTEMPTS = 3;
    
    protected static int totalUsers = 0;
    
    protected String name, username, password;
    protected boolean loggedIn, accountEnabled;
    protected int failedAttempts, ID;

    public User(String name, String username, String password)
    {
        this.name = name;
        this.username = username;
        this.password = password;
        loggedIn = false;
        accountEnabled = true;
        failedAttempts = 0;
        totalUsers++;
        ID = totalUsers;
    }
    
    public User()
    {
        this("default name", "default username", "password");
    }
    
    /*Factory method implementation 
     * @param userType Should be either Student, Instructor, or Administrator
     * @return A User of instance of userType
     */
    public static User createUser(String userType, String name, String username, String password){
        if("Administrator".equals(userType)){
            return new SystemAdmin(name, username, password);
        }
        else if("Instructor".equals(userType)){
            return new Instructor(name, username, password);
        }
        else if("Student".equals(userType)){
            return new Student(name, username, password);
        }
        else
            return null;
    }
    
    /**
     * Increments the failed attempt counter based on a bad login attempt.
     */
    public void incrementFailedAttempts()
    {
        failedAttempts++;
        if(failedAttempts > MAXATTEMPTS )
        {
            setAccountEnabled(false);
        }
    }
    
    public void resetFailedAttempts()
    {
        failedAttempts = 0;
    }
    
    public boolean isAccountEnabled() 
    {
        return accountEnabled;
    }

    public int getFailedAttempts() 
    {
        return failedAttempts;
    }

    public boolean isLoggedIn() 
    {
        return loggedIn;
    }

    public String getName() 
    {
        return name;
    }

    public String getPassword() 
    {
        return password;
    }

    public String getUsername() 
    {
        return username;
    }
    
    public int getID()
    {
        return ID;
    }

    public static int getTotalUsers()
    {
        return totalUsers;
    }
    
    public void setAccountEnabled(boolean accountEnabled) 
    {
        this.accountEnabled = accountEnabled;
    }

    public void setFailedAttempts(int failedAttempts) 
    {
        this.failedAttempts = failedAttempts;
    }

    public void setLoggedIn(boolean loggedIn) 
    {
        this.loggedIn = loggedIn;
    }

    public void setName(String name) 
    {
        this.name = name;
    }

    public void setPassword(String password) 
    {
        this.password = password;
    }

    public void setUsername(String username) 
    {
        this.username = username;
    }

    public static void setTotalUsers(int totalUsers)
    {
        User.totalUsers = totalUsers;
    }
    
    public String toString()
    {
        //Password not added for security purposes
        return name + " " + username;
    }
    
    public int compareTo(Object o)
    {
        return toString().compareTo(((User)o).toString());
    }
    
    /**
      * Save this object via serialization
      * 
      * @param filename the name of the file to save to
      */
     public void save(String filename) {
         try {
             /*
              * Create the object output stream for serialization.
              * We are wrapping a FileOutputStream since we
              * want to save to disk.  You can also save to socket
              * streams or any other kind of stream.
              */
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
            
            /*
             * The only real call we need.  The stream buffers the output and reuses
             * data, so if you are serializing very frequently, then the object values might
             * not actually change because the old serialized object is being reused.
             * 
             * To fix this you can try writeUnshared() or you can reset the stream.
             * out.reset();
             */
            out.writeObject(this);
        } catch (FileNotFoundException e) {
            Log.getInstance().log(Level.SEVERE, "Save file not found: " + filename, e);
        } catch (IOException e) {
            Log.getInstance().log(Level.SEVERE, "General IO Error on saving: " + filename, e);
        }
         
     }
    
}
